#ifndef SEM_H
#define SEM_H

#include <sys/ipc.h>
#include <sys/sem.h>
#include "testbase.h"

union semun
{
    int val;	//信号量的值
};

class Sem : public TestBase {
public:
    Sem(int argc=0, char** argv=nullptr)
        : TestBase(argc, argv)
        , valid(false)
    {
        key_t key = ftok(path, 1);
        semId = semget(key, 1, IPC_CREAT|IPC_EXCL|0666); // key=IPC_PRIVATE:进程独享  创建新的信号量（需要初始化）
        valid = semId!=-1;

        if(valid) {
            union semun tmp;
            tmp.val = 1;
            //第二参数是信号量集数组下标
            int ret = semctl(semId, 0, SETVAL, tmp);
            if(ret == -1) {
                puts("semctl setval fail");
                valid = false;
            }
        } else {
            semId = semget(key, 1, IPC_CREAT); // 获取已经存在的信号量
            valid = semId!=-1;
        }

        if(!valid) puts("semget fail");
    }

    //p操作
    void sem_p() {
        sembuf buf = {0, -1, SEM_UNDO}; // 下标 P操作 阻塞
        if(semop(semId, &buf, 1) == -1) { //第三个参数信号量的个数
            puts("semop p fail");
        }
    }

    //v操作
    void sem_v() {
        sembuf buf = {0, 1, SEM_UNDO};;
        if(semop(semId, &buf, 1) == -1) {
            puts("semop v fail");
        }
    }

    //销毁信号量集
    void sem_destroy()
    {
        //IPC_RMID是删除信号量集的ID
        //第二个参数起到占位作用
        if(semctl(semId, 0, IPC_RMID) == -1) {
            puts("destroy fail");
        }
    }

    void test() override {
        if(!valid) {
            puts("test fail");
            return;
        }

        puts("test...");
        sem_p();
        puts("p");
        std::this_thread::sleep_for(std::chrono::milliseconds(10000));
        sem_v();
        puts("v");
        puts("quit test");



    }

private:
    const char* path = "/temp";
    bool valid;
    int semId;
};

#endif // SEM_H
